<html>
<head>
  <title>Build a simple interpreter</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="684"/>
<h1>Build a simple interpreter</h1>

<div>
<span><div style="text-align: center;"><span><font style="font-size: 18pt; color: rgb(247, 255, 0);"><span style="line-height: 27px;"><b>Python语法部分</b></span></font></span></div><div><font style="font-size: 14pt; color: rgb(28, 51, 135);"><b>__str__和__repr__</b></font></div><div><span style="color: #000000;">如果要把一个类的实例变成 str，就需要实现特殊方法__str__()：</span></div><div><br/></div><div><span style="color: #0000ff;">class</span> <span style="color: #000000;">Person(object):</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, name, gender):</span></div><div><span style="color: #000000;">self.name</span> = <span style="color: #000000;">name</span></div><div><span style="color: #000000;">self.gender</span> = <span style="color: #000000;">gender</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):</span></div><div><span style="color: #0000ff;">return</span> <span style="color: #800000;">'</span><span style="color: #800000;">(Person: %s, %s)</span><span style="color: #800000;">'</span> % <span style="color: #000000;">(self.name, self.gender)</span></div><div><span style="color: #000000;">现在，在交互式命令行下用</span> <span style="color: #0000ff;">print</span> <span style="color: #000000;">试试：</span></div><div><br/></div><div>&gt;&gt;&gt; p = Person(<span style="color: #800000;">'</span><span style="color: #800000;">Bob</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">male</span><span style="color: #800000;">'</span><span style="color: #000000;">)</span></div><div>&gt;&gt;&gt; <span style="color: #0000ff;">print</span> <span style="color: #000000;">p</span></div><div><span style="color: #000000;">(Person: Bob, male)</span></div><div><span style="color: #000000;">但是，如果直接敲变量 p：</span></div><div><br/></div><div>&gt;&gt;&gt; <span style="color: #000000;">p</span></div><div>&lt;main.Person object at 0x10c941890&gt;</div><div><span style="color: #000000;">似乎__str__() 不会被调用。</span></div><div><br/></div><div><span style="color: #000000;">因为 Python 定义了__str__()和__repr__()两种方法，</span><span style="color: #800080;">__str__</span><span style="color: #000000;">()用于显示给用户，而__repr__()用于显示给开发人员。</span></div><div><br/></div><div><span style="color: #000000;">有一个偷懒的定义__repr__的方法：</span></div><div><br/></div><div><span style="color: #0000ff;">class</span> <span style="color: #000000;">Person(object):</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, name, gender):</span></div><div><span style="color: #000000;">self.name</span> = <span style="color: #000000;">name</span></div><div><span style="color: #000000;">self.gender</span> = <span style="color: #000000;">gender</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):</span></div><div><span style="color: #0000ff;">return</span> <span style="color: #800000;">'</span><span style="color: #800000;">(Person: %s, %s)</span><span style="color: #800000;">'</span> % <span style="color: #000000;">(self.name, self.gender)</span></div><div><span style="color: #800080;">__repr__</span> = <span style="color: #800080;">__str__</span></div><div><span style="color: #000000;">任务</span></div><div><span style="color: #000000;">请给Student 类定义__str__和__repr__方法，使得能打印出</span>&lt;Student: name, gender, score&gt;<span style="color: #000000;">：</span></div><div><br/></div><div><span style="color: #0000ff;">class</span> <span style="color: #000000;">Student(Person):</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, name, gender, score):</span></div><div><span style="color: #000000;">super(Student, self).</span><span style="color: #800080;">__init__</span><span style="color: #000000;">(name, gender)</span></div><div><span style="color: #000000;">self.score</span> = <span style="color: #000000;">score</span></div><div><span style="color: #000000;">?不会了怎么办</span></div><div><span style="color: #000000;">只要为Students 类加上__str__()和__repr__()方法即可。</span></div><div><br/></div><div><span style="color: #000000;">参考代码:</span></div><div><br/></div><div><span style="color: #0000ff;">class</span> <span style="color: #000000;">Person(object):</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, name, gender):</span></div><div><span style="color: #000000;">self.name</span> = <span style="color: #000000;">name</span></div><div><span style="color: #000000;">self.gender</span> = <span style="color: #000000;">gender</span></div><div><br/></div><div><span style="color: #0000ff;">class</span> <span style="color: #000000;">Student(Person):</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, name, gender, score):</span></div><div><span style="color: #000000;">super(Student, self).</span><span style="color: #800080;">__init__</span><span style="color: #000000;">(name, gender)</span></div><div><span style="color: #000000;">self.score</span> = <span style="color: #000000;">score</span></div><div><span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self):</span></div><div><span style="color: #0000ff;">return</span> <span style="color: #800000;">'</span><span style="color: #800000;">(Student: %s, %s, %s)</span><span style="color: #800000;">'</span> % <span style="color: #000000;">(self.name, self.gender, self.score)</span></div><div><span style="color: #800080;">__repr__</span> = <span style="color: #800080;">__str__</span></div><div><br/></div><div><span style="color: #000000;">s</span> = Student(<span style="color: #800000;">'</span><span style="color: #800000;">Bob</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">male</span><span style="color: #800000;">'</span>, 88<span style="color: #000000;">)</span></div><div><span style="color: #0000ff;">print</span> s</div><div><br/></div><div><br/></div><div style="text-align: center;"><font color="#F7FF00" style="font-size: 18pt;"><b>解释器</b></font></div><div style="text-align: center;"><br/></div><div><font style="font-size: 14pt; color: rgb(28, 51, 135);"><b>记号token</b></font></div><div><span>    <span>    </span></span>让解释器真正地理解怎么处理这一字符串，第一步需要将 “3+5”切分成不同的部分，我们称之为记号（tokens)。一个<span style="font-weight: bold;">记号（token)</span>是一对类型·值。举例来说，记号 “3”的类型为 INTEGER，相对应的值为整数3。</div><div><br/></div><div><font style="font-size: 14pt; color: rgb(28, 51, 135);"><b>词法分析器<span style="font-weight: bold; font-size: 14pt; color: rgb(28, 51, 135);">（lexical ananlyzer，简称lexer）</span></b></font></div><div><span>    <span>    </span></span>将输入的字符串切分成记号的过程被称作<font style="color: rgb(173, 0, 0);"><b>词法分析</b></font>。所以，第一步解释器需要读取输入并把它转换成一系列的记号。你也许碰到过其它的叫法，像<span style="font-weight: bold;">扫描程序</span>（scanner)，<span style="font-weight: bold;">分词器</span>（tokenizer)。它们意思都相同：解释器或者编译器中把输入字符串转换成一串记号的组件。Interpreter 类中的 <span style="font-style: italic;">get_next_token </span>方法就是一个词法分析器。</div><div><br/></div><div><font style="font-size: 14pt; color: rgb(28, 51, 135);"><b>查找结构并对其解释的方法是expr</b></font></div><div><span>    <span>    </span></span>expr 方法使用 <b><font style="color: rgb(173, 0, 0);">辅助方法(helper method) eat 来验证</font></b>传递给 eat 方法的记号类型与 current token 类型是否匹配。匹配成功 eat 方法获取下一个记号，并把下一个记号赋值给变量 current_token，如此实际上就把匹配的记号“吃掉了”，并把一个虚拟的指向记号流的指针向前移动了。如果在记号中的结构与所期望的 INTEGER PLUS INTEGER 序列不对等，eat 方法抛出一个异常。</div><div><br/></div><div><font style="font-size: 14pt; color: rgb(28, 51, 135);"><b>What is a lexeme?</b></font></div><div>A <span style="font-weight: bold;">lexeme</span> is a sequence of characters that form a token. In the following picture you can see some examples of tokens and sample lexemes and hopefully it will make the relationship between them clear:</div><div><img src="Build a simple interpreter_files/Image.png" type="image/png" data-filename="Image.png" width="543"/></div><div><br/></div><div><span style="font-weight: bold;"><font style="font-size: 14pt; color: rgb(28, 51, 135);">parsing</font></span></div><div><span style="line-height: 1.45;"><span>    <span>    </span></span>The process of finding the structure in the stream of tokens, or put differently, the process of recognizing a phrase in the stream of tokens is called</span> <span style="line-height: 1.45; font-weight: bold;">parsing</span><span style="line-height: 1.45;">. The part of an interpreter or compiler that performs that job is called a</span> <span style="line-height: 1.45; font-weight: bold;">parser</span><span style="line-height: 1.45;">.</span><br/></div><div><span style="-en-paragraph: true;"><span>    <span>    </span></span>So now you know that the</span> <span style="-en-paragraph: true; font-style: italic;">expr</span> <span style="-en-paragraph: true;">method is the part of your interpreter where both</span> <span style="-en-paragraph: true; font-weight: bold;">parsing</span> <span style="-en-paragraph: true;">and</span> <span style="-en-paragraph: true; font-weight: bold;">interpreting</span> <span style="-en-paragraph: true;">happens - the</span> <span style="-en-paragraph: true; font-style: italic;">expr</span> <span style="-en-paragraph: true;">method first tries to recognize (</span><span style="-en-paragraph: true; font-weight: bold;">parse</span><span style="-en-paragraph: true;">) the</span> <span style="-en-paragraph: true;">INTEGER</span> <span style="-en-paragraph: true;">-&gt;</span> <span style="-en-paragraph: true;">PLUS</span> <span style="-en-paragraph: true;">-&gt;</span> <span style="-en-paragraph: true;">INTEGER</span> <span style="-en-paragraph: true;">or the</span> <span style="-en-paragraph: true;">INTEGER</span> <span style="-en-paragraph: true;">-&gt;</span> <span style="-en-paragraph: true;">MINUS</span> <span style="-en-paragraph: true;">-&gt;</span> <span style="-en-paragraph: true;">INTEGER</span> <span style="-en-paragraph: true;">phrase in the stream of tokens and after it has successfully recognized (</span><span style="-en-paragraph: true; font-weight: bold;">parsed</span><span style="-en-paragraph: true;">) one of those phrases, the method interprets it and returns the result of either addition or subtraction of two integers to the caller.</span></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></span>
</div></body></html> 